/*
Kiwi Editor is a framework for building WYSIWYG web editors.
Copyright (C) 2011  Roosevelt de Lima Sardinha

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

Contact the author at roosevelt1@gmail.com (Roosevelt) 
*/

/**
 * The box that contains the instructions for using the editor. It can show any message when an event occurs, for instance.
 * @author Roosevelt de Lima Sardinha
 * @param {String} id The unique id of the instruction box
 * @param {Object} properties The object containing the properties to be initially set to the instruction box.
 * @constructor
 */
function instructionBox(id, properties)
{
	// Initialize some variables
	var thisObject = this;
	
	/**
	 * The workspace this instruction box belongs to.
	 * @type {Object}  
	 */
	this.workspace = properties.workspace;
	
	/**
	 * The object that contains the initial properties of the instruction box.
	 * @type {Object} 
	 */	
	this.properties = properties;
	
	/**
	 * The id of the instruction box.
	 * @type {String}
	 */
	this.id = id;
	
	/**
	 * The path of the CSS stylesheet file.
	 * @type {String}
	 */	
	this.cssPath = this.properties.cssPath ? this.properties.cssPath : "css/boxes/instructionBox.css";
	
	/**
	 * The title of this instruction box.
 	 * @type {String}
	 */	
	this.title = this.properties.title ? this.properties.title : "Help";
	
	/**
	 * The left coordinate of the instruction box.
	 * @type {Int}
	 */		
	this.left = this.properties.left ? parseInt(this.properties.left) : 0;
	
	/**
	 * The top coordinate of the instruction box.
	 * @type {Int}
	 */ 	
	this.top = this.properties.top ? parseInt(this.properties.top) : 0;
	
	/**
	 * The width of the property box.
	 * @type {Int}
	 */
	this.width = this.properties.width ? parseInt(this.properties.width) : 100;
	
	/**
	 * The height of the property box.
	 * @type {Int}
	 */		
	this.height = this.properties.height ? parseInt(this.properties.height) : 100;
	
	
	// Events
	/**
	 * <b>Event</b><br/>
	 * Defines what is going to be done when you drag the instruction box.
	 * @param {Int} x The left coordinate of the instruction box while dragging.
	 * @param {Int} y The top coordinate of the instruction box while dragging.
	 * @param {Object} instructionBox The instruction box being dragged.
	 */		
	this.onDrag = function(x,y, instructionBox){};
	
	/**
	 * <b>Event</b><br/>
	 * Defines what is going to be done when you drop the instruction box.
	 * @param {Int} x The left coordinate of the instruction box when dropped.
	 * @param {Int} y The top coordinate of the instruction box when dropped.
	 * @param {Object} instructionBox The instruction box being dropped.
	 */		
	this.onDrop = function(x,y, instructionBox){};
	
	/**
	 * <b>Event</b><br/>
	 * Defines what is going to be done when you start to resize the instruction box.
	 * @param {Int} width The width of the instruction box when you start to resize.
	 * @param {Int} height The height of the instruction box when you start to resize.
	 * @param {Object} instructionBox The instruction box being resized.
	 */		
	this.onBeforeResize = function(width, height, instructionBox){};
	
	/**
	 * <b>Event</b><br/>
	 * Defines what is going to be done during resize.
	 * @param {Int} width The width of the instruction box during resize.
	 * @param {Int} height The height of the instruction box during resize.
	 * @param {Object} instructionBox The instruction box being resized.
	 */	
	this.onResize = function(width, height, instructionBox){};
	
	/**
	 * <b>Event</b><br/>
	 * Defines what is going to be done after resize.
	 * @param {Int} width The width of the instruction box after resize.
	 * @param {Int} height The height of the instruction box after resize.
	 * @param {Object} instructionBox The instruction box resized.
	 */		
	this.onAfterResize = function(width, height, instructionBox){};
	
	/**
	 * <b>Event</b><br/>
	 * Defines what is going to be done when you remove this instruction box.
	 */	
	this.onRemove = function(){};
	
	/**
	 * <b>Event</b><br/>
	 * Defines what is going to be done when you restore the size of this instruction box.
	 * @param {Object} instructionBox The instruction box the size was restored.
	 */	
	this.onRestoreSize = function(instructionBox){};
	
	/**
	 * Defines what is going to be done when you setting a new text to the instruction box.
	 * @param {String} text The text you want to show in the box.
	 * @param {Object} instructionBox The instruction box the is going to show the text.
	 */
	this.onSetInstruction = function(text, instructionBox){};
	
	/**
	 * Defines what to do when you remove all the content of the instruction box.
	 * @param {Object} instructionBox
	 */
	this.onClear = function(instructionBox){};
	
		
	// Gets the initial size and position of the object.
	var iniLeft = parseInt(this.properties.left);
	var iniTop = parseInt(this.properties.top);
	var iniWidth = parseInt(this.properties.width);
	var iniHeight = parseInt(this.properties.height);

	/** 
	 * The id of the DOM node that contains this instruction box.
	 * @type {String}
	 */	
	this.parentId = this.properties.parent;
	// Gets the div where the div that has instructions is going to be inserted.	
	var parent = document.getElementById(this.parentId);

	// Creates the background div, the header and the div where the instruction is going to be added.
	var instructionBg = document.createElement('div');
	instructionBg.id = this.id + 'Bg';
	instructionBg.className = 'instruction-box';
	instructionBg.style.borderWidth = '4px';
	instructionBg.style.position = 'absolute';
	instructionBg.style.left = this.left + 'px';
	instructionBg.style.top = this.top + 'px';
	instructionBg.style.width = this.width + 'px';
	instructionBg.style.height = this.height + 'px';

	var instructionDiv = document.createElement('div');
	instructionDiv.id = this.id;
	instructionDiv.className = 'instruction-box-content';
	instructionDiv.style.position = 'absolute';
	instructionDiv.style.left = this.left + parseInt(instructionBg.style.borderLeftWidth) + 'px';
	instructionDiv.style.top = this.top + parseInt(instructionBg.style.borderTopWidth) + 'px';
	instructionDiv.style.width = this.width + 'px';
	instructionDiv.style.height = this.height + 'px';

	var instructionHeader =  document.createElement('div');
	instructionHeader.id = this.id + 'Header';
	instructionHeader.className = 'instruction-box-header';
	instructionHeader.innerHTML = this.title;
	instructionHeader.ondblclick = function() {	
		thisObject.setLeft(iniLeft);
		thisObject.setTop(iniTop);
		thisObject.setWidth(iniWidth);
		thisObject.setHeight(iniHeight);
		thisObject.onRestoreSize(thisObject);
	};

	var instructionText =  document.createElement('div');
	instructionText.id = this.id + 'Text';
	instructionText.className = 'instruction-box-text';
	instructionText.innerHTML = '';

	parent.appendChild(instructionDiv);
	parent.appendChild(instructionBg);
	instructionDiv.appendChild(instructionHeader);
	instructionDiv.appendChild(instructionText);
	
	// Make the divs resizable.
	$('#' + this.id).resizable({
		start: function(event,ui){
			thisObject.onBeforeResize(document.getElementById(thisObject.id).offsetWidth, document.getElementById(thisObject.id).offsetHeight, thisObject);
		},
		resize: function(event,ui){
			thisObject.setWidth(document.getElementById(this.id).offsetWidth);
			thisObject.setHeight(document.getElementById(this.id).offsetHeight);
			thisObject.onResize(document.getElementById(thisObject.id).offsetWidth, document.getElementById(thisObject.id).offsetHeight, thisObject);
			},
		stop:  function(event,ui){
			thisObject.setWidth(document.getElementById(this.id).offsetWidth);
			thisObject.setHeight(document.getElementById(this.id).offsetHeight);
			thisObject.onAfterResize(document.getElementById(thisObject.id).offsetWidth, document.getElementById(thisObject.id).offsetHeight, thisObject);
			},
		containment:'#' + parent.id, 
		minWidth: 100, 
		minHeight: 50,
		maxWidth: 1024,
		maxHeight: 768});

	// Make the divs draggable.
	$('#' + this.id).draggable(
		{handle:'#' + this.id +'Header',
		containment: '#' + parent.id,
		drag: function(event,ui){
			thisObject.setTop(document.getElementById(thisObject.id).offsetTop);
			thisObject.setLeft(document.getElementById(thisObject.id).offsetLeft);
			thisObject.onDrag(document.getElementById(thisObject.id).offsetTop, document.getElementById(thisObject.id).offsetLeft, thisObject);
			},
		stop: function(event,ui){
			thisObject.setTop(document.getElementById(this.id).offsetTop);
			thisObject.setLeft(document.getElementById(this.id).offsetLeft);			
			thisObject.onDrop(document.getElementById(thisObject.id).offsetTop, document.getElementById(thisObject.id).offsetLeft, thisObject);
			}
		});

	var fixedInstruction = false;

	/**
	 * Sets the text to be shown in the instruction box.
	 * @param {String} text The text that is going to appear.
	 * @param {Boolean} fixed Makes the instruction not possible to clear, but you can set another one and change the attribute.
	 */
	this.setInstruction = function(text, fixed)
	{
		// Updates the instruction written in the box.
		instructionText.innerHTML = text;
		//Fixed attribute makes the instruction not possible to clear, but you can set another one and change the attribute.
		fixedInstruction = fixed;
		this.onSetInstruction(text, this);
	}
	
	/**
	 * Gets the text in the instruction box.
	 * @return The text it shows.
	 * @type {String}
	 */
	this.getInstruction = function()
	{
		// Returns the instruction in the box.
		return instructionText.innerHTML = text; 
	}

	/**
	 * Removes everything written in the instruction box.
	 */
	this.clearInstruction = function()
	{
		// Makes the instruction box clean, without any text.
		if (fixedInstruction == false)
		{
			instructionText.innerHTML = '';
		}
		this.onClear(this);
	}

	/**
	 * Sets the left property of the instruction box. 
	 * @param {Int} left The left coordinate to be set.
	 */
	this.setLeft = function(left){
		instructionBg.style.left = left + 'px';
		if (navigator.appName != "Microsoft Internet Explorer")
		{
			instructionDiv.style.left = left + parseInt(instructionBg.style.borderLeftWidth) + 'px';
		}
		else
		{
			instructionDiv.style.left = left  + 'px';
		}
		this.left = left;	
	}	

	/**
	 * Sets the top property of the instruction box
	 * @param {Int} top The top coordinate to be set.
	 */
	this.setTop = function(top){
		instructionBg.style.top = top + 'px';
		if (navigator.appName != "Microsoft Internet Explorer")
		{
			instructionDiv.style.top = top + parseInt(instructionBg.style.borderTopWidth) + 'px';	
		}
		else
		{
			instructionDiv.style.top = top + 'px';	
		}
		this.top = top;
	}	

	/**
	 * Sets the width of the instruction box.
	 * @param {Int} width The width to be set.
	 */
	this.setWidth =	function(width){
		instructionBg.style.width = width + 'px';
		instructionDiv.style.width = width + 'px';	
		instructionText.style.width = width - 5 + 'px';
		this.width = width;
	}	

	/**
	 * Sets the height of the instruction box.
	 * @param {Int} height The height to be set.
	 */
	this.setHeight = function (height){
		instructionBg.style.height = height + 'px';
		instructionDiv.style.height = height + 'px';	
		instructionText.style.height = height - 25 + 'px';	
		this.height = height;
	}	
	
	/**
	 * Sets the title of the instruction box. 
	 * @param {String} title The new title to be set.
	 */	
	this.setTitle = function(title){
		instructionHeader.innerHTML = title;
		this.title = title;
	}

	/**
	 * Changes a property of the instruction box to some value
	 * @param {String} propertyName The name of the property to be changed.
	 * @param {Any} value The value to be set to the property.
	 */		
	this.setProperty = function(propertyName, value){
		switch(propertyName){
			case 'height':
				this.setHeight(value);
				break;
			
			case 'width':
				this.setWidth(value);
				break;
				
			case 'top':
				this.setTop(value);
				break;
			
			case 'left':
				this.setLeft(value);
				break;
				
			case 'title':
				this.setTitle(value);
				break;
			
			case 'cssPath':
				this.setCSS(value);
				break;
			
			default:
				document.write('Property not found');
				break;
		}
	}

	this.setLeft(this.left);
	this.setTop(this.top);
	this.setWidth(this.width);
	this.setHeight(this.height);
	
	/**
	 * Removes this instruction box.
	 */
	this.remove = function(){
		instructionDiv.parentNode.removeChild(instructionDiv);
		instructionBg.parentNode.removeChild(instructionBg);
		instructionHeader.parentNode.removeChild(instructionHeader);
		delete instructionDiv;
		delete instructionBg;
		delete instructionHeader;
		this.onRemove();
	}
	
	/**
	 * Sets a new CSS stylesheet to the instruction box.
	 * @param {String} path The relative path of the CSS stylesheet file from the APP_HOME folder.
	 */		
	this.setCSS = function(path){
		this.workspace.setCSS(this, path);
	}
	this.setCSS(this.cssPath);
}
